﻿#include "OiPCH.hpp"
#include <QtConcurrent/QtConcurrentRun>

namespace Oi
{
    namespace PLScannerCore
    {

        class CalibDlgImpl : public Impl<CalibDlg>
        {
        public:
            void init();

            void calibDone(const double value);

        public:
            static void valueUpdate(const double&, void*);

        public:
            void readTemperature();

        public:
            QLineEdit* _measurePos;
            QLineEdit* _measure;
            QLineEdit* _actual;
            QPushButton* _calib;
            QPushButton* _zero;
        public:
            QList<double> _values;
            QLabel* _msg;

        public:
            double _temperature1;
            double _temperature2;
            QFuture<void> _future;
           // QPushButton* _cancel;

        };

        void CalibDlgImpl::init()
        {
            OI_Q(CalibDlg);

            q->setWindowTitle(CalibDlg::tr("定点标定"));

            QGridLayout* layout = new QGridLayout(q);

            QLabel* mpL = new QLabel("测量位置");
            QLabel* ml = new QLabel("测量值");
            QLabel* al = new QLabel("实际值");
            _measurePos = new QLineEdit("0.00");
            _measurePos->setValidator(new QDoubleValidator());
            _measure = new QLineEdit("0.00");
            _measure->setValidator(new QDoubleValidator());
            _measure->setReadOnly(true);
            _actual = new QLineEdit("0.00");
            _actual->setValidator(new QDoubleValidator());

            _measurePos->setText(QString::number(Core::OiSettings()->value("Calib/CalibPos", 0.0).toDouble(), 'f', 2));
            _actual->setText(QString::number(Core::OiSettings()->value("Calib/ActuralValue", 0.0).toDouble(), 'f', 2));

            _calib = new QPushButton("开始标定");
            _zero = new QPushButton("定位0点");
            //_cancel = new QPushButton("取消");

            _msg = new QLabel();
            _msg->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
            layout->addWidget(ml, 0, 0);
            layout->addWidget(_measure, 0, 1);
            layout->addWidget(al, 1, 0);
            layout->addWidget(_actual, 1, 1);
            layout->addWidget(mpL, 2, 0);
            layout->addWidget(_measurePos, 2, 1);

            layout->addWidget(_calib, 4, 0);
            layout->addWidget(_zero, 4, 1);

            layout->addWidget(_msg, 5, 1);

            mpL->hide();
            _measurePos->hide();
            _zero->hide();

           // layout->addWidget(_cancel, 3, 1);

            q->connect(_calib, &QPushButton::clicked, q, &CalibDlg::onCalib);
            q->connect(_zero, &QPushButton::clicked, q, &CalibDlg::onZero);

           // q->connect(_cancel, &QPushButton::clicked, q, &QDialog::reject);

        }

        void CalibDlgImpl::calibDone(const double value)
        {
            OI_Q(CalibDlg);

            QMetaObject::invokeMethod(q, "onCalibDone", Qt::AutoConnection, Q_ARG(double, value));
        }

        void CalibDlgImpl::valueUpdate(const double& value, void* data)
        {
            auto impl = reinterpret_cast<CalibDlgImpl*>(data);
            if (impl)
            {
                impl->calibDone(value);
            }
        }

        void CalibDlgImpl::readTemperature()
        {
            SensorAcquire::OiAcquire()->readTemperature(_temperature1, _temperature2);
        }

        CalibDlg::CalibDlg(QWidget* parent /*= nullptr*/)
        {
            OI_I(CalibDlg)->init();
        }

        CalibDlg::~CalibDlg()
        {
            SensorAcquire::OiAcquire()->abort();
        }

        void CalibDlg::onCalib()
        {
            OI_F(CalibDlg);

            d->_actual->setEnabled(false);
            d->_calib->setEnabled(false);
            d->_measurePos->setEnabled(false);
            d->_zero->setEnabled(false);
            //d->_cancel->setEnabled(false);

            bool convert = false;
            double actualValue = d->_actual->text().toDouble(&convert);

            if (!convert)
            {
                OiAlerter() << tr("实际值有错误，标定不成功");
                return;
            }

            double measurePos = d->_measurePos->text().toDouble(&convert);

            if (!convert)
            {
                OiAlerter() << tr("测量位置有错误，标定不成功");
                return;
            }

            d->_temperature1 = 0.0;
            d->_temperature2 = 0.0;

            d->_future = QtConcurrent::run(d, &CalibDlgImpl::readTemperature);

            Core::OiSettings()->setValue("Calib/ActuralValue", actualValue);
            Core::OiSettings()->setValue("Calib/CalibPos", measurePos);
            PLScanner::instance()->calibPos = measurePos;
            Core::OiSettings()->sync();
        
            double retValue = 0.0;
            if (SensorAcquire::OiAcquire()->acquire(CalibDlgImpl::valueUpdate, d, retValue, measurePos, false, 100))
            {
                d->_msg->setText("<font color = \"#008000\"> 正在标定</font>");
            }
            else
            {
                d->_msg->setText("<font color = \"#ff0000\">标定不成功</font>");
                OiAlerter() << tr("获取测量值不成功，标定不成功");
                return;
            }
        }

        void CalibDlg::onCalibDone(double value)
        {
            OI_F(CalibDlg);
            d->_values.append(value);

            if (d->_values.size() > 20)
            {
//                 auto wideCalib_A = Core::OiSettings()->value("Calib/WideCalib-A", 0.0).toDouble();
//                 auto wideCalib_B = Core::OiSettings()->value("Calib/WideCalib-B", 0.0).toDouble();
// 
//                 auto wideOffset = wideCalib_A * PLScanner::instance()->calibPos + wideCalib_B;
// 
//                 OiWarning() << "单点标定位，位置补偿值：" << wideOffset;

                double wideOffset = 0.0;

                double mvalue = PLScannerUtil::medianV(d->_values);
                d->_actual->setEnabled(true);
                d->_calib->setEnabled(true);
                d->_measurePos->setEnabled(true);
                d->_zero->setEnabled(true);
                d->_measure->setText(QString::number(mvalue, 'f', 2));

                double actualValue = d->_actual->text().toDouble();

                PLScanner::instance()->measureOffsetY = actualValue - mvalue - wideOffset;

                SensorAcquire::OiAcquire()->abort();

                PLScanner::instance()->saveCalibRecord(d->_temperature1, d->_temperature2, mvalue);

                d->_msg->setText("<font color = \"#008000\">标定成功</font>");
            }
        }

        void CalibDlg::onZero()
        {
            OI_F(CalibDlg);

            d->_actual->setEnabled(false);
            d->_calib->setEnabled(false);
            d->_measurePos->setEnabled(false);
            d->_zero->setEnabled(false);

            Motor::instance()->locateMode();
            if (!Motor::instance()->isReady())
            {
                d->_msg->setText("<font color = \"#ff0000\">轴状态不正确</font>");
                goto ZERO_END;
            }

            Motor::instance()->locatedRun(0.0);

            QThread::msleep(1000);

            d->_msg->setText("<font color = \"#008000\">正在等待轴运动至0点</font>");

            int timerCounter = 0;

            while (!Motor::instance()->locatedModeReady())
            {
                QEventLoop loop;
                QTimer::singleShot(100, &loop, SLOT(quit()));
                loop.exec();

                timerCounter++;

                if (timerCounter > 100)
                {
                    d->_msg->setText("<font color = \"#ff0000\">轴运动超时</font>");
                    goto ZERO_END;
                }
            }

            d->_msg->setText("<font color = \"#008000\">定位成功</font>");

        ZERO_END:
            d->_actual->setEnabled(true);
            d->_calib->setEnabled(true);
            d->_measurePos->setEnabled(true);
            d->_zero->setEnabled(true);
        }

    }
}